#ifndef __LOG__
#define __LOG__
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <memory>
#include <fstream>
#include <filesystem>
#include <sstream>
#include<ctime>
#include<cstdio>
#include "mutex.hpp"
using namespace std;
#define gsep "\r\n"
// 基类：
class Logstrategy
{
public:
    Logstrategy() {}
    virtual void synclog(const string &message) = 0;
    ~Logstrategy() {}
};

// 控制台打印日志：

class consolelogstrategy : public Logstrategy
{

public:
    consolelogstrategy() {}
    void synclog(const string &message) override
    {
        // 加锁完成多线程互斥：
        {
            mutexguard md(_mutex);
            cout << message << gsep;
        }
    }
    ~consolelogstrategy() {}

private:
    mutex _mutex;
};

// 自定义文件打印日志：
const string P = "./log";
const string F = "my.log";
class fileLogstrategy : public Logstrategy
{

public:
    fileLogstrategy(const string path = P, const string file = F) : _path(path), _file(file)
    {
        // 如果指定路径(目录)不存在进行创建；否则构造直接返回：
        {
            mutexguard md(_mutex);
            if (filesystem::exists(_path))
                return;
            try
            {
                filesystem::create_directories(_path);
            }
            catch (filesystem::filesystem_error &e)
            {
                cout << e.what() << gsep;
            }
        }
    }

    void synclog(const string &message) override
    {
        // 得到指定文件名：
        {
            mutexguard md(_mutex);
            string name = _path + (_path.back() == '/' ? "" : "/") + _file;
            // 打开文件进行<<写入：
            ofstream out(name, ios::app); // 对某文件进行操作的类对象
            if (!out.is_open())
                return; // 成功打开
            out << message << gsep;
            out.close();
        }
    }
    ~fileLogstrategy() {}

private:
    string _path;
    string _file;
    mutex _mutex;
};

// 用户调用日志+指定打印：
// 日志等级：
enum class loglevel
{
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
};
// 完成枚举值对应由数字到原值转化：
string trans(loglevel &lev)
{

    switch (lev)
    {
    case loglevel::DEBUG:
        return "DEBUG";
    case loglevel::INFO:
        return "INFO";
    case loglevel::WARNING:
        return "WARNING";
    case loglevel::ERROR:
        return "ERROR";
    case loglevel::FATAL:
        return "FATAL";
    default:
        return "ERROR";
    }
    return"";
}

// 从时间戳提取出当前时间：
string  gettime()
{
   time_t curtime=time(nullptr);
    struct tm t;
    localtime_r(&curtime,&t);
    char buff[1024];
    sprintf(buff,"%4d-%02d-%02d %02d:%02d:%02d",
        t.tm_year+1900,//注意struct tm成员性质
        t.tm_mon+1,
        t.tm_mday,
        t.tm_hour,
        t.tm_min,
        t.tm_sec
    );
    return buff;
     
}
class Log
{
public:
    // Log刷新策略：
    void console() { _fflush_strategy = make_unique<consolelogstrategy>(); }
    void file() { _fflush_strategy = make_unique<fileLogstrategy>(); }
    Log()
    {
        // 默认是控制台刷新：
        console();
    }
    // 我们想让一个类重载了<<支持连续的<<输入并且希望每行结束就进行刷新；因此这个meesage类
    // 析构就可以执行刷新；-->内部类天然就是外部类的友元类；可以访问外部类所有成员变量及函数
    class Logmess
    {
    public:
        Logmess(loglevel &lev, string filename, int line, Log &log) : _lev(lev),
         _time(gettime()), _pid(getpid()), _filename(filename), _log(log), _linenum(line)
        {

            stringstream ss;
            ss << "[" << _time << "] "
               << "[" << trans(_lev) << "] "
               << "[" << _pid << "] "
               << "[" << _filename << "] "
               << "[" << _linenum << "] "
               << "<--> ";
               _mergeinfo=ss.str();
        }
         template<class T>
         Logmess& operator <<(const T& data){
            stringstream ss;
              ss<<data;
            _mergeinfo +=ss.str();
            return *this;
         }
        ~Logmess()
        {
            _log._fflush_strategy->synclog(_mergeinfo);
        }

    private:
        loglevel _lev;
        string _time;
        pid_t _pid;
        string _filename;
        int _linenum;
        string _mergeinfo;
        Log &_log;
    };

    Logmess operator()(loglevel l,string f,int le)
    {   //返回的是匿名对象（临时对象）-->也就是作用完当前行
        //（执行完logmess的<< <<后自动调用logmess的析构也就是直接策略打印）      
         return Logmess(l,f,le,*this);
    }
    ~Log() {}

private:
    unique_ptr<Logstrategy> _fflush_strategy;
};

 Log l;
 #define use_log(x) l(x,__FILE__,__LINE__)//自动判断是哪行哪个文件
 #define filestrategy l.file()
 #define  consolestrategy l.console()
#endif